﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Reflection.Emit;
using System.Reflection;

namespace SyringeControl.ControlConfiguration
{
    public interface IConfigurationStore
    {
    }

    public interface IControlConfiguration
    {
        void Apply(Control control);

        void Save(IConfigurationStore store);
        void Load(IConfigurationStore store);
    }

    public interface IEventLogger
    {
        void Handle(object sender, object args);
    }

    public interface IAdapterBuilder
    {
        bool CanBuild(Type delegateType);
        Delegate BuildAdapter(Type delegateType, IEventLogger handler);
    }
    interface IAdapterBuilder<TEventType> : IAdapterBuilder
    {
    }

    class EventHandlerBuilder: IAdapterBuilder<EventHandler>
    {
        #region Члены IAdapterBuilder

        public bool CanBuild(Type delegateType)
        {
            if (!typeof(Delegate).IsAssignableFrom(delegateType))
                return false;
            var parameters = delegateType.GetMethod("Invoke").GetParameters();
            return parameters.Length == 2
                && parameters[0].ParameterType == typeof(object)
                && typeof(EventArgs).IsAssignableFrom(parameters[1].ParameterType);

        }

        public Delegate BuildAdapter(Type delegateType, IEventLogger handler)
        {
            var handlingMethod = handler.GetType().GetMethod("Handle", new[] { typeof(object), typeof(object) });
            return Delegate.CreateDelegate(delegateType, handler, handlingMethod);
        }

        #endregion
    }

    class ActionAdapterBuilder : IAdapterBuilder<Action>
    {
        #region Члены IAdapterBuilder

        public bool CanBuild(Type delegateType)
        {
            return delegateType == typeof(Action);
        }

        public Delegate BuildAdapter(Type delegateType, IEventLogger handler)
        {
            return new Action(() => handler.Handle(null, null));
        }

        #endregion
    }

    class Action1AdapterBuilder : IAdapterBuilder
    {
        public bool CanBuild(Type delegateType)
        {
            return delegateType.GetGenericTypeDefinition() == typeof(Action<>);
        }

        public Delegate BuildAdapter(Type delegateType, IEventLogger handler)
        {
            var parameters = delegateType.GetMethod("Invoke").GetParameters();
            var realHandler = typeof(OneArgHandler<>).MakeGenericType(parameters[0].ParameterType);
            var handlingFunction = realHandler.GetMethod("Handle");
            return Delegate.CreateDelegate(delegateType, Activator.CreateInstance(realHandler, handler), handlingFunction);
        }

        class OneArgHandler<T>
        {
            IEventLogger Logger;
            public OneArgHandler(IEventLogger logger)
            {
                Logger = logger;
            }
            public void Handle(T arg)
            {
                Logger.Handle(arg, null);
            }
        }
    }

    class GenericEventHandlerAdapterFactory : IAdapterBuilder
    {
        IList<IAdapterBuilder> _builders = new IAdapterBuilder[] { 
            new EventHandlerBuilder(), 
            new ActionAdapterBuilder(),
            new Action1AdapterBuilder()
        };

        public bool CanBuild(Type eventType)
        {
            return _builders.Any(builder => builder.CanBuild(eventType));
        }

        public Delegate BuildAdapter(Type eventType, IEventLogger handler)
        {
            if (handler == null)
                return null;
            foreach(var builder in _builders)
                if(builder.CanBuild(eventType))
                    return builder.BuildAdapter(eventType, handler);
            throw new NotSupportedException("adapting to event type "+eventType+" is not supported");
        }
        public TDelegate BuildAdapter<TDelegate>(IEventLogger handler)
            where TDelegate: class
        {
            return BuildAdapter(typeof(TDelegate), handler) as TDelegate;
        }
    }

    class TraceEventLogger : IEventLogger
    {
        public void Handle(object sender, object args)
        {
            Trace.WriteLine(String.Format("{0}: {1}", sender, args));
        }

        public override string ToString()
        {
            return "trace";
        }
    }

    class MessageBoxEventLogger : IEventLogger
    {
        public void Handle(object sender, object args)
        {
            MessageBox.Show(args.ToString(), sender.ToString(), MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        public override string ToString()
        {
            return "message box";
        }
    }

    class NullEventLogger : IEventLogger
    {
        public void Handle(object sender, object args)
        {
        }

        public override string ToString()
        {
            return "none";
        }
    }

    //class EventHandlersConfiguration: IContr
    //{
    //}
}
